package dataPersistence;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import common.Result;
import common.ValueResult;

import facades.ItemFacade;
import facades.ProductFacade;
import facades.StorageFacade;
import hitExceptions.InvalidOperationException;
import coreModel.HIT;
import coreModel.Item;
import coreModel.ItemManager;
import coreModel.Product;
import coreModel.ProductContainer;
import coreModel.ProductGroup;
import coreModel.ProductManager;
import coreModel.SerializableImplementer;
import coreModel.StorageUnit;
import dataPersistence.dao.IProductDAO;
import dataPersistence.dao.IProductGroupDAO;
import dataPersistence.dao.IStorageUnitDAO;
import dataPersistence.dao.Item_DB_DAO;
import dataPersistence.dao.ProductGroup_DB_DAO;
import dataPersistence.dao.Product_DB_DAO;
import dataPersistence.dao.StorageUnit_DB_DAO;
import dataPersistence.dto.ItemDTO;
import dataPersistence.dto.ProductContainerDTO;
import dataPersistence.dto.ProductDTO;
import dataPersistence.dto.ProductGroupDTO;
import dataPersistence.dto.StorageUnitDTO;

public class DB_DAOFactory extends SerializableImplementer implements DataPersistenceFactory{

	/**
	 * returns the item DAO
	 * @return Item_DB_DAO
	 */
	@Override
	public Item_DB_DAO getItemDAO(){
		return new Item_DB_DAO();
	}


	/**
	 * returns the product DAO
	 * @return Product_DB_DAO
	 */
	@Override
	public IProductDAO getProductDAO()
	{
		return new Product_DB_DAO();
	}


	/**
	 * returns the product group DAO
	 * @return ProductGroup_DB_DAO
	 */
	@Override
	public IProductGroupDAO getProductGroupDAO(){
		return new ProductGroup_DB_DAO();
	}


	/**
	 * returns the storage unit DAO
	 * @return StorageUnit_DB_DAO
	 */
	@Override
	public IStorageUnitDAO getStorageUnitDAO(){
		return new StorageUnit_DB_DAO();
	}


	@Override
	public void save(String file) throws InvalidOperationException
	{
		save();

	}

	@Override
	public void save() throws InvalidOperationException
	{
		// do nothing

	}

	@Override
	public void load(String file) throws InvalidOperationException
	{
		load();

	}


	@Override
	public void load() throws InvalidOperationException
	{
		HIT.getInstance().setLoadingFromDataBase(true);
		Result result = new Result();
		result =TransactionManager.begin();
		if(!result.getStatus()) 
		{
			System.err.println(result.getMessage());
		}

		loadSUnits();
		loadPGroups();
		loadProducts();
		loadItems();
		loadRemovedItems();
		
		TransactionManager.end(false);
		HIT.getInstance().setLoadingFromDataBase(false);
	}

	private void loadSUnits()
	{
		System.out.println("in the load SU");
		StorageUnit_DB_DAO suDAO = new StorageUnit_DB_DAO();
		HashSet<StorageUnitDTO> sUnits = new HashSet<StorageUnitDTO>();

		ValueResult<Set<StorageUnitDTO>> result = suDAO.getAllStorageUnits();

		if (result.getStatus())
			sUnits = (HashSet<StorageUnitDTO>) result.getValue();
		else
		{
			System.err.println(result.getMessage());
		}
		for (StorageUnitDTO unit : sUnits)
		{
			System.out.println(unit.getName());
			StorageUnit tmp = unit.convertToModelObject();
			StorageFacade.getInstance().addStorageUnit( tmp );
			HIT.getInstance().getProductManager().addConatiner(tmp);
			HIT.getInstance().getItemManager().addContainer(tmp);

		}
	}

	private void loadPGroups()
	{
		IProductDAO pgDAO = HIT.getInstance().getFactory().getProductDAO();
		IStorageUnitDAO suDAO = HIT.getInstance().getFactory().getStorageUnitDAO();

		Set<StorageUnitDTO> allUnits = suDAO.getAllStorageUnits().getValue();

		//add all the children for each su
		for( StorageUnitDTO su : allUnits)
		{
		
			recursiveAdd(su);
			
		}

	}

	private Result recursiveAdd(ProductContainerDTO su)
	{
		//init dao
		Result result = new Result();
		IStorageUnitDAO suDAO = HIT.getInstance().getFactory().getStorageUnitDAO();

		//get list of children
		ValueResult<ArrayList<ProductContainerDTO>> childrenOfThis = suDAO.getChildren(su.getProductContainerID());

		//check for errors
		if(!childrenOfThis.getStatus())
		{
			System.err.println(childrenOfThis.getMessage());
			result.setMessage(childrenOfThis.getMessage());
			return result;
		}

		for(ProductContainerDTO child : childrenOfThis.getValue())
		{
			// add the child before recursing
			ProductGroup tmpGroup = ((ProductGroupDTO) child).convertToModelObject();

			ProductContainer tmpContainer=HIT.getInstance().getStorageUnitManager().getContainerByID(su.getProductContainerID());
			try
			{
				;
				tmpContainer.addProductGroup(tmpGroup);
				// add the child's children
			
				result= recursiveAdd(child);
				if(!result.getStatus())
				{
					System.err.println(result.getMessage());
					return result;
				}
			}
			catch (Exception e)
			{

				e.printStackTrace();
				result.setStatus(false);
				return result;
			}
		}
		result.setStatus(true);
		return result;

	}


	private boolean PCExists(ProductContainer pc)
	{
		ItemManager iMgr = HIT.getInstance().getItemManager();
		ProductManager pMgr = HIT.getInstance().getProductManager();

		if (iMgr.hasContainer(pc) && pMgr.hasContainer(pc))
			return true;
		else if ( !iMgr.hasContainer(pc) && !pMgr.hasContainer(pc))
			return false;
		else
			throw new RuntimeException("Item and Product Managers are out of " +
			"sync for ProductGroups");
	}

	private void loadProducts()
	{
		Product_DB_DAO pDAO = new Product_DB_DAO();
		HashSet<ProductDTO> pList = new HashSet<ProductDTO>();

		ValueResult<Set<ProductDTO>> result = pDAO.getAllProducts();

		if ( result.getStatus() )
			pList = (HashSet<ProductDTO>) result.getValue();



		for (ProductDTO pDTO : pList)
		{
			Product p = pDTO.convertToModelObject();


			updateContainers(p);

			//			for (ProductContainer container : p.getContainers())
			//				ProductFacade.getInstance().addProduct(p, container);
		}

	}	

	private void updateContainers(Product p)
	{
		Product_DB_DAO pDAO = new Product_DB_DAO();
		ValueResult<ArrayList<String>> result = pDAO.getAllParentsOfProduct(p.getBarcode().getValue());
		ArrayList<String> container_ids = new ArrayList<String>();

		if (result.getStatus())
			container_ids = result.getValue();

		for (String id : container_ids)
		{
			ProductContainer tmp = HIT.getInstance().getStorageUnitManager().getContainerByID(id);
			try
			{
				p.addContainerToProdcutList(tmp);
			} catch (InvalidOperationException e)
			{
				e.printStackTrace();
			}
		}

	}


	private void loadItems()
	{
		Item_DB_DAO iDAO = new Item_DB_DAO();
		ArrayList<ItemDTO> iList = new ArrayList<ItemDTO>();

		ValueResult<Collection<ItemDTO>> result = iDAO.getAllItems();
		if(!result.getStatus()) System.err.println(result.getMessage());

		if (result.getStatus())
			iList = (ArrayList<ItemDTO>) result.getValue();

		for (ItemDTO iDTO : iList)
		{
			Item i = iDTO.convertToModelObject();
			ItemFacade.getInstance().addItem(i);
		}

	}

	private void loadRemovedItems()
	{
		Item_DB_DAO iDAO = new Item_DB_DAO();
		ArrayList<ItemDTO> iList = new ArrayList<ItemDTO>();
		
		ValueResult<Collection<ItemDTO>> result = iDAO.getAllDeleteItems();
		if(!result.getStatus())
			System.err.println(result.getMessage());

		if (result.getStatus())
			iList = (ArrayList<ItemDTO>) result.getValue();

		for (ItemDTO iDTO : iList)
		{
			Item i = iDTO.convertToModelObject();
			HIT.getInstance().getItemHistory().addItem(i, true);
		}
	}
	

}
